package com.itrip.log.core;

import java.util.concurrent.CopyOnWriteArraySet;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;

import sun.misc.Signal;
import sun.misc.SignalHandler;

/**
 * Function:统一管理系统推出事件
 *
 * @date:2016年6月8日/下午9:07:44
 * @Author:coder_czp@126.com
 * @version:1.0
 */
@SuppressWarnings("restriction")
public class ShutdownCallbackManger extends Thread implements SignalHandler, ApplicationListener<ContextRefreshedEvent> {

	/**
	 * 支持捕获的信号:<br>
	 * window:SEGV, ILL, FPE, ABRT, INT, TERM, BREAK SYS, CPU, FSZ, ABRT, INT,
	 * TERM, HUP, USR1, USR2, QUIT, BREAK, TRAP, PIPE TERM（kill -15）、USR1（kill
	 * -10）、USR2（kill -12） linux: SEGV, ILL, FPE, BUS,
	 */
	private String signalNames;

	private volatile boolean hasExecute = false;

	private static final Logger log = LoggerFactory.getLogger(ShutdownCallbackManger.class);

	private CopyOnWriteArraySet<ShutdownCallback> callbacks = new CopyOnWriteArraySet<ShutdownCallback>();

	public void setSignalNames(String signalNames) {
		this.signalNames = signalNames;
	}

	public void addCallback(ShutdownCallback callback) {
		callbacks.add(callback);
	}

	public CopyOnWriteArraySet<ShutdownCallback> getCallbacks() {
		return callbacks;
	}

	public void registHook() {
		try {
			Runtime.getRuntime().addShutdownHook(this);
			for (String name : signalNames.split(",")) {
				Signal.handle(new Signal(name), this);
			}
			log.info("success regist for:{}", signalNames);
		} catch (Exception e) {
			log.error("fill to regist signal", e);
		}
	}

	@Override
	public void run() {
		hasExecute = true;
		for (ShutdownCallback call : callbacks) {
			try {
				call.onSystemExit();
				log.info("sucess to call:{}", call);
			} catch (Exception e) {
				log.error("fail to call:{}", call, e);
			}
		}
	}

	@Override
	public void handle(Signal arg0) {
		log.info("recive signal:{}", arg0);
		if (!hasExecute)
			run();
	}

	@Override
	public void onApplicationEvent(ContextRefreshedEvent event) {
		ApplicationContext ctx = event.getApplicationContext();
		callbacks.addAll(ctx.getBeansOfType(ShutdownCallback.class).values());
		log.info("regist ShutdownCallback:{}", ctx.getBeansOfType(ShutdownCallback.class));
	}

}
